条件语句的多层嵌套问题优化,助你写出不让同事吐槽的代码
The following article is from 月伴飞鱼 Author 日常加油站
本文经月伴飞鱼(id:gh_c4183eee9eb9)授权转载
如若转载请联系原公众号
前言
《阿里巴巴开发手册》中,有关于多 if-else 分支和嵌套的建议和解决方案,如下:
案例
下面是开发中可能会遇到的典型代码:
public String getTweetTitle(int type) {
String result;
if (type == 0) {
throw new IllegalArgumentException("参数有误");
}
//长贴-->获得长帖标题
if (isPaperTweet(type)) {
result = getPaperTweetTitle();
} else {
// 视频贴-->获得视频贴标题
if (isVideoTweet(type)) {
result = getVideoTitle();
} else {
result = getDefaultTitle();
}
}
return result;
}
这种情况,我们如何替代多分支和分支嵌套问题呢?如何让代码变得更容易维护和拓展呢?
可以先自己思考一下哈..........
下面我提供几种方法吧
卫语句
《重构--改善既有代码的设计》 书籍中有有如下描述:
如果某个条件极其罕见,就应该单独检查该条件,并在条件为真时立即从函数中返回。这样的单独检查常常被称为 “卫语句”。
public String getTweetTitle(int type) {
// 条件检查
if (type == 0) {
throw new IllegalArgumentException("参数有误");
}
// 长贴-->获得长帖标题
if (isPaperTweet(type)) {
return getPaperTweetTitle();
}
// 视频贴-->获得视频贴标题
if (isVideoTweet(type)) {
return getVideoTitle();
}
return getDefaultTitle();
}
先进行条件检查,然后将 if-else 逻辑转成对应的卫语句格式。
枚举
《Effective Java 中文版》 中第 30 条 :用 enum 代替 int 常量 小节有描述:使用枚举,来替代分支语句,虽然失去了简洁性,但是更加安全和灵活。
通过在枚举内部定义抽象函数,每个枚举常量重写该函数,这样根据枚举值获取枚举常量后调用该函数即可获得期待的计算结果。
示例代码如下:
public enum TweetStrategyEnum {
PAPER(1) {
@Override
double getTitle() {
return "长贴标题";
}
},
VIDEO_TWEET(2) {
@Override
double getTitle() {
return "视频贴标题";
}
},
DEFAULT_TWEET(3) {
@Override
double getTitle() {
return "短贴标题";
}
};
private final int type;
TweetStrategyEnum(int type) {
this.type = type;
}
abstract String getTitle();
public static TweetStrategyEnum valueOf(int type) {
for (TweetStrategyEnum tweetStrategyEnum : TweetStrategyEnum.values()) {
if (tweetStrategyEnum.type == type) {
return tweetStrategyEnum;
}
}
return null;
}
}
使用时根据枚举值获取枚举对象,直接调用该枚举常量对应的策略:
public void getTitle() {
TweetStrategyEnum tweetStrategyEnum = TweetStrategyEnum.valueOf(1);
if(tweetStrategyEnum != null){
System.out.println(tweetStrategyEnum.getTitle());
}
}
状态模式
《设计模式之禅》 状态模式章节中讲到:
状态模式的其中一个优点就是 “结构清晰”。状态模式体现了开闭原则和单一职责原则,易于拓展和维护。
所谓的结构清晰就是避免了过多的 switch-case 或者 if-else 语句的使用,避免了程序的复杂性,提高了程序的可维护性。
《设计模式之禅》书提供的案例和文章上面给出的非常类似,根据当前状态来执行不同的行为,有兴趣可以翻出看看
同样优化下上面的案例代码:
定义一个状态行为接口
public interface TweetState {
String getTitle();
}
定义多个具体的状态实现
public class VideoTweetState implements TweetState{
@Override
public String getTitle() {
return "视频贴";
}
}
public class PaperTweetState implements TweetState{
@Override
public String getTitle() {
return "长贴标题";
}
}
public class DefaultTweetState implements TweetState{
@Override
public String getTitle() {
return "短贴标题";
}
}
定义一个状态使用的client
public class Client {
private TweetState tweetState;
public TweetState getTweetState() {
return tweetState;
}
public void setTweetState(TweetState tweetState) {
this.tweetState = tweetState;
}
public void getTitle() {
tweetState.getTitle();
}
}
外部使用
public static void main(String[] args) {
Client client = new Client();
client.setTweetState(new VideoTweetState());
client.getTitle();
}
策略+工厂模式
首先,我们把每个条件逻辑代码块,抽象成一个公共的接口,可以得出以下代码:
public interface ITweetService {
String getTitle();
}
我们根据每个逻辑条件,定义相对应的策略实现类,可得以下代码:
public class PaperTweetServiceImpl implements ITweetService{
@Override
public String getTitle() {
return "长贴标题";
}
}
public class VideoTweetServiceImpl implements ITweetService{
@Override
public String getTitle() {
return "视频贴标题";
}
}
接下来,我们再定义策略工厂类,用来管理这些策略类,如下:
public class TweetServicesFactory {
private static final Map<String, ITweetService> map = new HashMap<>();
static {
map.put("paperTweet", new PaperTweetServiceImpl());
map.put("videoTweet", new VideoTweetServiceImpl());
}
public static ITweetService getTweetService(String type) {
return map.get(type);
}
}
public static void main(String[] args) {
ITweetService tweetService = TweetServicesFactory.getITweetService(1);
tweetService.getTitle();
}
总结
本文主要讲了如何解决 if-else 语句拓展性和多层嵌套问题。可以通过卫语句、枚举、状态模式、策略+工厂模式等方式解决,如果大家有更好的方案,可以留言区聊一聊~
<END>
程序员专属T恤